/******************************************************************************/
package jamie.org.sil.www.usxUtils;




/******************************************************************************/
/**
   A footnote marker manager.
   <p>

   When you have a footnote, it is common practice in printing to insert
   some character into the main text to indicate the reference -- typically
   a dagger or a double dagger, or a superscripted letter or number.
   <p>

   In USFM (and therefore by implication in USX), the character to be
   used for this purpose is indicated indirectly by what the USFM
   standard refers to as a <i>caller</i>.  If this is anything other
   than a plus sign or a minus sign, then it is the character to be
   inserted into the output.  If it is a plus-sign, then it is up to
   the processing here to make up its mind as to what character string
   to use; and in theory if it is a minus sign, then no character is
   to be output (and possibly, although I am not entirely clear from
   the USFM specification), the footnote is to be skipped altogether).
   I say "in theory", because the USFM standard then goes on to say
   that the minus sign is never used in practice.
   <p>

   Note that originally I assumed that having established a particular
   way of handling footnotes markers, you would always handle them in
   the same way -- that if you wanted to specify a particular marker,
   you would <i>always</i> specify particular markers; and that if you
   wanted to leave it to the processing to make up its own mind, you
   would always do so.  On reflection, I am not so certain this is the
   case -- I don't think USFM lays down any such constraint, and I have
   therefore attempted to extend the processing in the present file to
   address this, although this extended code has yet to be tried in
   anger.
   <p>

   As will be seen, therefore, processing where you do <i>not</i> have
   a plus-sign as the caller is relatively straightforward.  Where you
   <i>do</i>, the present class interacts with relevant configuration
   information in order to determine how to arrive at a suitable
   character string.
   <p>
   
   By way of summary :-
   <ul>
   <li><i>footnoteMarkers</i> may be either the word "numeric", or else a space-
       separated list of markers.  If it's numeric, then the footnote
       markers are numeric and increment from one reference to the next.
       Otherwise the markers run over the list of markers in order.
       Where the marker list is used, markers would typically be single
       characters, but in fact any string will do.</li>

   <li><i>footnoteMarkerResetAt</i> may be "Never", "Book", "Chapter" or "Verse",
       and determines where we restart the numbering from 1, or where
       we restart the list if we are using a list of markers.  I can't
       imagine "Verse" would ever be used, and I imagine "Book", if it's
       used at all, will only be on printed texts.</li>

   <li><i>footnoteMarkerStyle</i> may be "Circulate" or "Increment", and is
       relevant only where you are using a list of markers (ie not where
       you are using numerics -- in fact if you're using numerics, the
       style is forced to be "Increment" even if "Circulate" is
       stipulated).  It says whether, when we run out of further options
       on the list, the next marker starts again with the first one,
       or whether we start doubling up, so that if the markers were $, % and ^,
       then ^ would be followed by $$.</li>
   </ul>

   Note that I do not currently make any provision to use letters rather than
   numbers for incrementing markers -- ie I can't go a, b, c, etc.  This would
   be difficult, since without appropriate information from the translator, I
   do not necessarily know which are the alphabetic characters, nor what order
   they run in.
   <p>

   The caller must call newBook, newChapter and newVerse at appropriate times
   so that the class knows when to reset markers.
   <p>

   It may sometimes be useful to know, not the marker which should be
   used <i>now</i>, but the marker which was issued most recently (for
   example if you first need to insert a footnote reference in the
   main text, and then want to put that same marker into the footnote
   text itself).  The method getMostRecentFootnoteMarker caters for this.
   <p>

   The world at large may also (via <i>setPrefix</i> and
   <i>setSuffix</i>) define a string to be output before and after the
   actual marker itself.  This is useful where, for instance, you want to
   arrange for the marker to be superscripted, because you can arrange to
   have the text which performs superscripting to be output.
*/

public class FootnoteMarkerManager
{
  /****************************************************************************/
  /****************************************************************************/
  /**                                                                        **/
  /**                                Public                                  **/
  /**                                                                        **/
  /****************************************************************************/
  /****************************************************************************/

  /****************************************************************************/
  /**
   * Decrements the counter.  Useful in situations where, for example, we've
   * just put a footnote marker into the notes without yet actually having
   * encountered the place which refers to them.
   */

  public void decrement ()
  {
    if (m_LastMarkerCausedAnIncrement) --m_Count;
  }


  /****************************************************************************/
  /**
     Set the prefix.

     @param prefix
   */
  public void setPrefix (String prefix)
  {
    m_Prefix = prefix;
  }


  /****************************************************************************/
  /**
     Set the suffix.

     @param suffix
   */
  public void setSuffix (String suffix)
  {
    m_Suffix = suffix;
  }


  /****************************************************************************/
  /**
     Note that some combinations of configuration parameters are illegal, but
     I don't do any checking.

     @param np Numeral processor (used when handling numeric markers).
  */
  
  public FootnoteMarkerManager (NumeralProcessor np)
  {
    /**********************************************************************/
    m_NumeralProcessor = np;



    /**********************************************************************/
    String s = Config.instance().getFootnoteMarkers().trim();
    m_Markers = s.split("\\s+");
    if ("numeric".equalsIgnoreCase(m_Markers[0])) m_Markers = null;



    /**********************************************************************/
    s = Config.instance().getFootnoteMarkerResetAt();
    if ("Never".equalsIgnoreCase(s))
      m_FootnoteMarkerResetAt = C_Never;
    else if ("Book".equalsIgnoreCase(s))
      m_FootnoteMarkerResetAt = C_Book;
    else if ("Chapter".equalsIgnoreCase(s))
      m_FootnoteMarkerResetAt = C_Chapter;
    else if ("Verse".equalsIgnoreCase(s))
      m_FootnoteMarkerResetAt = C_Verse;
    


    /**********************************************************************/
    /* Note that "Circulate" does not make sense with numeric markers. */
    
    s = Config.instance().getFootnoteMarkerStyle();
    if ("Circulate".equalsIgnoreCase(s))
      m_FootnoteMarkerStyle = (null == m_Markers ? C_Increment : C_Circulate);
    else if ("Increment".equalsIgnoreCase(s))
      m_FootnoteMarkerStyle = C_Increment;
  }


  /****************************************************************************/
  /**
     Get a footnote marker.

     @param caller As defined in USFM and USFMX, defines what character we
                   actually want to return.  

     @return Footnote marker.
  */

  public String getFootnoteMarker (String caller)
  {
    /*------------------------------------------------------------------------*/
    if (!"+".equals(caller))
    {
      m_LastMarkerCausedAnIncrement = false;
      setMostRecentFootnoteMarker(caller);
      return getMostRecentFootnoteMarkerDecorated();
    }
    


    /*------------------------------------------------------------------------*/
    String s = "";
    switch (m_FootnoteMarkerStyle)
    {
      case C_Circulate:
        s =  m_Markers[m_Count % m_Markers.length];
        break;

      case C_Increment:
        if (null == m_Markers)  // This condition flags that we're using numeric markers.
          s = m_NumeralProcessor.toVernacular(1 + m_Count);
        else
        {
          int n = m_Count;
          if (n < 0) throw new ConverterException(ConverterException.Action.AbandonFileWhenever, ConverterException.Log.Error, "Problem with footnote markers.  Check the configuration information ties up with the details in your confif files.");
          
          while (true)
          {
            s = m_Markers[n % m_Markers.length] + s;
            if (1 == m_Markers.length) break;
            n /= m_Markers.length;
            if (0 == n) break;
            --n;
          }
        }
        break;
    }

    ++m_Count;
    m_LastMarkerCausedAnIncrement = true;
    setMostRecentFootnoteMarker(s);
    return getMostRecentFootnoteMarkerDecorated();
  }


  /****************************************************************************/
  /**
     Gets the most recently issued footnote marker.

     @return Footnote marker.
  */

  public String getMostRecentFootnoteMarker ()
  {
    return m_MostRecentFootnoteMarker;
  }


  /****************************************************************************/
  /**
     Gets the most recently issued footnote marker, along with any decoration.

     @return Footnote marker.
  */

  public String getMostRecentFootnoteMarkerDecorated ()
  {
    return m_Prefix + m_MostRecentFootnoteMarker + m_Suffix;
  }
  
  
  /****************************************************************************/
  /**
     Resets counts when we hit a new book.
  */

  public void newBook ()
  {
    if (C_Book == m_FootnoteMarkerResetAt) m_Count = 0;
  }


  /****************************************************************************/
  /**
     Resets counts when we hit a new chapter.
  */

  public void newChapter ()
  {
    if (C_Chapter == m_FootnoteMarkerResetAt) m_Count = 0;
  }


  /****************************************************************************/
  /**
     Resets counts when we hit a new verse.
  */

  public void newVerse ()
  {
    if (C_Verse == m_FootnoteMarkerResetAt) m_Count = 0;
  }


  /****************************************************************************/
  /**
     Forcibly resets the count.
  */

  public void resetCount ()
  {
    m_Count = 0;
  }





  /****************************************************************************/
  /****************************************************************************/
  /**                                                                        **/
  /**                                Private                                 **/
  /**                                                                        **/
  /****************************************************************************/
  /****************************************************************************/

  /****************************************************************************/
  /* Set the record of the most recently issued footnote marker. */

  private void setMostRecentFootnoteMarker (String s)
  {
    m_MostRecentFootnoteMarker = s;
  }
  
  
  private static final int C_Never = 0;
  private static final int C_Book = 1;
  private static final int C_Chapter = 2;
  private static final int C_Verse = 3;

  public static final int C_Circulate = 0;
  public static final int C_Increment = 1;

  private String[] m_Markers = null;
 
  private int m_Count = 0;
  private int m_FootnoteMarkerResetAt = C_Book;
  private int m_FootnoteMarkerStyle = C_Circulate;

  private boolean m_LastMarkerCausedAnIncrement = false;
  
  private String m_MostRecentFootnoteMarker = "";

  private String m_Prefix = "";
  private String m_Suffix = "";

  private NumeralProcessor m_NumeralProcessor = null;
}